/*
 * @Author: zwf 240970521@qq.com
 * @Date: 2023-07-22 00:22:32
 * @LastEditors: zwf 240970521@qq.com
 * @LastEditTime: 2023-08-02 00:57:54
 * @FilePath: /esp32_motor/adc/adc.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_continuous.h"
#include "adc.h"
#include "pin.h"
#include <string.h>
#include "esp_adc/adc_cali.h"
#include "math_common.h"

#define ADC1_FILTER_SIZE 4

/*只支持管理ADC1*/
#define ADC1_MAX_CHANNEL 8
#define ADC1_BASE_PIN    32
#define ADC1_INDEX(pin)  ((pin)-ADC1_BASE_PIN)

typedef struct
{
    bool                    init[ADC1_MAX_CHANNEL];
    int                     channel[ADC1_MAX_CHANNEL];
    AdcData                 data[ADC1_MAX_CHANNEL];
    int                     registerCnt;
    adc_continuous_handle_t handle;
    adc_cali_handle_t       caliHandle;
} AdcManager;

static AdcManager adcManager = {
    .channel = {ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7, ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2,
                ADC_CHANNEL_3},
};

/*adc中断回调*/
static bool IRAM_ATTR ADC_isrCb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    char    *buf                   = edata->conv_frame_buffer;
    uint64_t sum[ADC1_MAX_CHANNEL] = {0};
    int      cnt[ADC1_MAX_CHANNEL];

    memset(sum, 0, sizeof(sum));
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < edata->size; i += SOC_ADC_DIGI_RESULT_BYTES)
    {
        adc_digi_output_data_t *p       = (adc_digi_output_data_t *)&buf[i];
        uint32_t                chanNum = p->type1.channel;
        uint32_t                data    = p->type1.data;

        /*准备均值滤波*/
        sum[chanNum] += data;
        cnt[chanNum]++;
    }

    for (int i = 0; i < ADC1_MAX_CHANNEL; i++)
    {
        if (cnt[i] != 0)
        {
            /*这里的i代表channel*/
            adcManager.data[i].isOk    = true;
            adcManager.data[i].rawData = sum[i] / cnt[i];
            /*数据校准*/
            adc_cali_raw_to_voltage(adcManager.caliHandle, adcManager.data[i].rawData, &adcManager.data[i].voltage);
            // if (i==ADC_CHANNEL_3)continue;
            /*低通滤波*/
            adcManager.data[i].voltage     = (5 * adcManager.data[i].voltage + 95 * adcManager.data[i].prevVoltage) / 100;
            adcManager.data[i].prevVoltage = adcManager.data[i].voltage;
        }
    }

    return true;
}

/*注册adc*/
esp_err_t ADC_register(int pin)
{
    if (PIN_register(pin, PIN_ADC))
    {
        return ESP_FAIL;
    }
    /*已经被注册过*/
    if (adcManager.init[ADC1_INDEX(pin)])
    {
        return ESP_FAIL;
    }

    adcManager.init[ADC1_INDEX(pin)] = true;
    adcManager.registerCnt++;
    return ESP_OK;
}

esp_err_t ADC_init(void)
{
    int n = 0;

    /*配置*/
    adc_continuous_handle_cfg_t adcConfig = {
        .max_store_buf_size = 2 * ADC1_FILTER_SIZE * adcManager.registerCnt * 4,
        .conv_frame_size    = 2 * ADC1_FILTER_SIZE * adcManager.registerCnt,
        .flags.flush_pool   = 1,
    };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&adcConfig, &adcManager.handle));

    adc_continuous_config_t digCfg = {
        .sample_freq_hz = 300 * 1000,
        .conv_mode      = ADC_CONV_SINGLE_UNIT_1,
        .format         = ADC_DIGI_OUTPUT_FORMAT_TYPE1,
    };

    adc_digi_pattern_config_t *adcPattern = NULL;
    /*临时内存申请*/
    adcPattern = calloc(adcManager.registerCnt, sizeof(adc_digi_pattern_config_t));
    if (!adcPattern)
    {
        goto free;
    }
    // printf("cnt = %d\n", adcManager.registerCnt);
    for (int i = 0; i < ADC1_MAX_CHANNEL; i++)
    {
        if (adcManager.init[i])
        {
            adcPattern[n].atten     = ADC_ATTEN_DB_11;
            adcPattern[n].bit_width = ADC_BITWIDTH_12;
            adcPattern[n].channel   = adcManager.channel[i];
            adcPattern[n++].unit    = ADC_UNIT_1;
            // printf("i = %d, channel = %d\n", i, adcManager.channel[i]);
        }
    }
    digCfg.pattern_num = adcManager.registerCnt;
    digCfg.adc_pattern = adcPattern;
    ESP_ERROR_CHECK(adc_continuous_config(adcManager.handle, &digCfg));
    /*注册回调*/
    adc_continuous_evt_cbs_t cbs = {
        .on_conv_done = ADC_isrCb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adcManager.handle, &cbs, NULL));

    adc_cali_line_fitting_config_t caliConfig = {
        .unit_id  = ADC_UNIT_1,
        .atten    = ADC_ATTEN_DB_11,
        .bitwidth = ADC_BITWIDTH_12,
    };
    ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&caliConfig, &adcManager.caliHandle));

    adc_continuous_start(adcManager.handle);
    free(adcPattern);

    return ESP_OK;
free:
    free(adcPattern);
    return ESP_FAIL;
}

AdcData IRAM_ATTR ADC_getData(int pin)
{
    return adcManager.data[adcManager.channel[ADC1_INDEX(pin)]];
}
